/*
 * Matrix.cs
 * 
 * Copyright (c) 2005, dnAnalytics. All rights reserved.
*/

#region Using Directives
using System;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using dnAnalytics.Exceptions;
using dnAnalytics.Resources;
using dnAnalytics.LinearAlgebra.Decomposition;
#endregion Using Directives

namespace dnAnalytics.LinearAlgebra
{
    /// <summary>
    /// Abstract matrix class.
    /// </summary>
    public abstract class Matrix : IFormattable, ICloneable
    {
        #region Fields
        private readonly int rows;
        private readonly int columns;
        #endregion Fields

        #region Properties
        /// <summary>
        /// Set or get an element of the matrix.
        /// </summary>
        /// <param name="row">The row index.</param>
        /// <param name="column">The column index.</param>
        /// <returns>A specific element in the matrix.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If either the row or column index is outside the 
        /// the dimensions of this matrix.</exception>
        public virtual double this[int row, int column]
        {
            get
            {
                RangeCheck(row, column);
                return ValueAt(row, column);
            }
            set
            {
                RangeCheck(row, column);
                ValueAt(row, column, value);
            }
        }

        /// <summary>
        /// The number of columns.
        /// </summary>
        public int Columns
        {
            get
            {
                return columns;
            }
        }

        /// <summary>
        /// The numbers of rows.
        /// </summary>        
        public int Rows
        {
            get
            {
                return rows;
            }
        }

        #endregion Properties

        #region Protected Methods
        /// <summary>
        /// Sets the number of rows and columns for the matrix.
        /// </summary>
        /// <param name="rows">The number of rows.</param>
        /// <param name="columns">The number of columns.</param>
        protected Matrix(int rows, int columns)
        {
            this.rows = rows;
            this.columns = columns;
        }

        /// <summary>
        /// Creates a <b>Matrix</b> for the given number of rows and columns.
        /// </summary>
        /// <param name="numberOfRows">The number of rows.</param>
        /// <param name="numberOfColumns">The number of columns.</param>
        /// <returns>A <b>Matrix</b> with the given dimensions.</returns>
        protected abstract Matrix CreateMatrix(int numberOfRows, int numberOfColumns);

        /// <summary>
        /// Retrieves the value at the given indices. Note: This method is not ranged checked. If the
        /// indices are outside the dimensions of the matrix, it may return an incorrect value or throw
        /// an <see cref="IndexOutOfRangeException"/>.
        /// </summary>
        /// <param name="row">The row index.</param>
        /// <param name="column">The column index.</param>
        /// <returns>The value at the given indices.</returns>
        /// <exception cref="IndexOutOfRangeException">Depending on the implementation, an <see cref="IndexOutOfRangeException"/>
        /// may be thrown if one of the indices is outside the dimensions of the matrix.</exception>
        protected internal abstract double ValueAt(int row, int column);

        /// <summary>
        /// Set the value at the given indices to the given value. Note: This method is not ranged checked. If the
        /// indices are outside the dimensions of the matrix, it may set an incorrect element or throw
        /// an <see cref="IndexOutOfRangeException"/>.
        /// </summary>
        /// <param name="row">The row index.</param>
        /// <param name="column">The column index.</param>
        /// <param name="value">The value to set.</param>
        /// <exception cref="IndexOutOfRangeException">Depending on the implementation, an <see cref="IndexOutOfRangeException"/>
        /// may be thrown if one of the indices is outside the dimensions of the matrix.</exception>
        protected internal abstract void ValueAt(int row, int column, double value);

        #endregion Protected Methods

        #region Public Methods

        /// <summary>Calculates the Frobenius norm of this matrix.</summary>
        /// <returns>The Frobenius norm of this matrix.</returns>
        public virtual double FrobeniusNorm()
        {
            Matrix tmp = this * this.Transpose();

            double ret = 0;
            for (int i = 0; i < Rows; i++)
            {
                ret += System.Math.Abs(tmp.ValueAt(i, i));
            }
            return System.Math.Sqrt(ret);
        }

        /// <summary>Calculates the infinity norm of this matrix.</summary>
        /// <returns>The infinity norm of this matrix.</returns>      
        public virtual double InfinityNorm()
        {
            double ret = double.NegativeInfinity;
            for (int i = 0; i < Rows; i++)
            {
                double s = 0;
                for (int j = 0; j < Columns; j++)
                {
                    s += System.Math.Abs(this.ValueAt(i, j));
                }
                ret = System.Math.Max(ret, s);
            }
            return ret;
        }

        /// <summary>Calculates the L1 norm of this matrix.</summary>
        /// <returns>The L1 norm of this matrix.</returns>
        public virtual double L1Norm()
        {
            // the 1-norm (or largest column sum) of a matrix,
            double norm = double.NegativeInfinity;
            for (int j = 0; j < Columns; j++)
            {
                double columnSum = 0;
                for (int i = 0; i < Rows; i++)
                {
                    columnSum += System.Math.Abs(ValueAt(i, j));
                }
                norm = System.Math.Max(norm, columnSum);
            }
            return norm;
        }

        /// <summary>Calculates the L2 norm of this matrix.</summary>
        /// <returns>The L2 norm of this matrix.</returns>   
        /// <remarks>For sparse matrices, the L2 norm is computed using a dense implementation of singular value decomposition. 
        /// In a later release, it will be replaced with a sparse implementation.</remarks>
        /// <exception cref="NotSupportedException">If the library is running on MS Windows and using <b>CLAPACK</b>
        /// as the <see cref="dnAnalytics.LinearAlgebra.Native.LapackProvider"/>.</exception>
        /// <remarks><b>This method is not supported under MS Windows when using the CLAPACK library.</b></remarks>
        public virtual double L2Norm()
        {
            if (Settings.UseNativeLibrary && Settings.Lapack == dnAnalytics.LinearAlgebra.Native.LapackProvider.Clapack && Environment.OSVersion.Platform != PlatformID.Unix)
            {
                throw new NotSupportedException(Strings.ClapackNotSupported);
            }
            Svd svd = new Svd(this, false);
            return svd.Norm2();
        }

        /// <summary>
        /// Sets all values to zero.
        /// </summary>
        public virtual void Clear()
        {
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Columns; j++)
                {
                    this.ValueAt(i, j, 0);
                }
            }
        }

        /// <summary>
        /// Copies a column into a vector.
        /// </summary>
        /// <param name="index">The column to copy.</param>
        /// <returns>A <see cref="Vector"/> containing the copied elements.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of columns.</exception>
        public virtual Vector Column(int index)
        {
            return Column(index, new Range(0, rows - 1));
        }

        /// <summary>
        /// Copies a column into to the given vector.
        /// </summary>
        /// <param name="index">The column to copy.</param>
        /// <param name="result">The <see cref="Vector"/> to copy the column into.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of columns.</exception>
        /// <exception cref="NotConformableException">If <b>this.Rows != result.Count</b>.</exception>
        public virtual void Column(int index, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (result.Count != Rows)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            if (index >= Columns || index < 0)
            {
                throw new ArgumentOutOfRangeException("index", Strings.OutOfRangeException);
            }
            this.Column(index, new Range(0, rows - 1), result);
        }

        /// <summary>
        /// Copies the given <see cref="Range"/> of a column into a vector.
        /// </summary>
        /// <param name="index">The column to copy.</param>
        /// <param name="range">The <see cref="Range"/> of elements to copy from the requested column.</param>
        /// <returns>A <see cref="Vector"/> containing the copied elements.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="range"/> specifies a range
        /// outside the column's range. </exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of columns.</exception>        
        public virtual Vector Column(int index, Range range)
        {
            Vector result = VectorBuilder.CreateVector((range.End - range.Start) / range.Stride + 1, VectorType.Dense);
            Column(index, range, result);
            return result;
        }

        /// <summary>
        /// Copies the given <see cref="Range"/> of a column into the given vector.
        /// </summary>
        /// <param name="index">The column to copy.</param>
        /// <param name="range">The <see cref="Range"/> of elements to copy from the requested column.</param>
        /// <param name="result">The <see cref="Vector"/> to copy the column into.</param>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="range"/> specifies a range
        /// outside the column's range. </exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of columns.</exception>        
        /// <exception cref="NotConformableException">If <b>result.Count != (range.End - range.Start) / range.Stride + 1</b>.</exception>
        public virtual void Column(int index, Range range, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (index >= Columns || index < 0)
            {
                throw new ArgumentOutOfRangeException("index", Strings.OutOfRangeException);
            }
            if (range.Start >= Rows || range.End >= Rows)
            {
                throw new ArgumentOutOfRangeException("range", Strings.OutOfRangeException);
            }
            for (int i = range.Start, j = 0; i <= range.End; i += range.Stride, j++)
            {
                result[j] = this.ValueAt(i, index);
            }
        }

        /// <summary>
        /// Returns an <see cref="IEnumerator{T}"/> that enumerates the columns of this matrix.
        /// </summary>
        /// <param name="range">The <paramref name="range"/> of columns to enumerate over.</param>
        /// <returns>An <see cref="IEnumerator{T}"/> that enumerates over a given <see cref="Range"/> of columns of this matrix.</returns>
        /// <remarks>The enumerator returns a <seealso cref="KeyValuePair{T,K}"/> with the key being the column index and the value 
        /// being the that column as a <see cref="Vector"/>.</remarks>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="range"/> specifies a range of columns that is
        /// outside the number of matrix columns. </exception> 
        /// <seealso cref="KeyValuePair{T,K}"/>
        /// <seealso cref="IEnumerator{T}"/>
        /// <include file='../../../examples/trunk/LinearAlgebra/MatrixColumnEnumeratorRange.xml' path='example'/> 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public virtual IEnumerable<KeyValuePair<int, Vector>> ColumnEnumerator(Range range)
        {
            if (range.Start >= Columns || range.End >= Columns)
            {
                throw new ArgumentOutOfRangeException("range", Strings.OutOfRangeException);
            }
            for (int i = range.Start; i <= range.End; i += range.Stride)
            {
                yield return new KeyValuePair<int, Vector>(i, Column(i));
            }
        }

        /// <summary>
        /// Returns an <see cref="IEnumerator{T}"/> that enumerates the columns of this matrix.
        /// </summary>
        /// <returns>An <see cref="IEnumerator{T}"/> that enumerates over a given <see cref="Range"/> of columns of this matrix.</returns>
        /// <remarks>The enumerator returns a <see cref="KeyValuePair{T,K}"/> with the key being the column index and the value 
        /// being the that column as a <see cref="Vector"/>.</remarks>
        /// <seealso cref="KeyValuePair{T,K}"/>
        /// <seealso cref="IEnumerator{T}"/>
        /// <include file='../../../examples/trunk/LinearAlgebra/MatrixColumnEnumerator.xml' path='example'/> 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public virtual IEnumerable<KeyValuePair<int, Vector>> ColumnEnumerator()
        {
            for (int i = 0; i < Columns; i++)
            {
                yield return new KeyValuePair<int, Vector>(i, Column(i));
            }
        }

        /// <summary>
        /// Copies a row into an <see cref="Vector"/>.
        /// </summary>
        /// <param name="index">The row to copy.</param>
        /// <returns>A <see cref="Vector"/> containing the copied elements.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of rows.</exception>
        public virtual Vector Row(int index)
        {
            return Row(index, new Range(0, columns - 1));
        }

        /// <summary>
        /// Copies a row into to the given <see cref="Vector"/>.
        /// </summary>
        /// <param name="index">The row to copy.</param>
        /// <param name="result">The  <see cref="Vector"/> to copy the row into.</param>
        /// <exception cref="ArgumentNullException">if the result matrix is <b>null</b>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of rows.</exception>
        /// <exception cref="NotConformableException">If <b>this.Columns != result.Count</b>.</exception>
        public virtual void Row(int index, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (result.Count != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            if (index >= Rows || index < 0)
            {
                throw new ArgumentOutOfRangeException("index", Strings.OutOfRangeException);
            }
            Row(index, new Range(0, columns - 1), result);
        }

        /// <summary>
        /// Copies the given <see cref="Range"/> of a row into an <see cref="Vector"/>.
        /// </summary>
        /// <param name="index">The column to copy.</param>
        /// <param name="range">The <see cref="Range"/> of elements to copy.</param>
        /// <returns>A <see cref="Vector"/> containing the copied elements.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="range"/> specifies a range
        /// outside the row's range. </exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of rows.</exception>    
        /// <remarks>The abstract matrix class returns a dense vector be default.</remarks>
        public virtual Vector Row(int index, Range range)
        {
            Vector result = VectorBuilder.CreateVector((range.End - range.Start) / range.Stride + 1, VectorType.Dense);
            Row(index, range, result);
            return result;
        }

        /// <summary>
        /// Copies the given <see cref="Range"/> of a row into an <see cref="Vector"/>.
        /// </summary>
        /// <param name="index">The column to copy.</param>
        /// <param name="range">The <see cref="Range"/> of elements to copy.</param>
        /// <param name="result">The <see cref="Vector"/> to copy the row into.</param>
        /// <returns>A <see cref="Vector"/> containing the copied elements.</returns>
        /// <exception cref="ArgumentNullException">if the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>result.Count != (range.End - range.Start) / range.Stride + 1</b>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="range"/> specifies a range
        /// outside the row's range. </exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is negative,
        /// or greater than or equal to the number of rows.</exception>    
        public virtual void Row(int index, Range range, Vector result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (index >= Rows || index < 0)
            {
                throw new ArgumentOutOfRangeException("index", Strings.OutOfRangeException);
            }
            if (range.Start >= this.Columns || range.End >= this.Columns)
            {
                throw new ArgumentOutOfRangeException("range", Strings.OutOfRangeException);
            }

            for (int i = range.Start, j = 0; i <= range.End; i += range.Stride, j++)
            {
                result[j] = this.ValueAt(index, i);
            }

        }

        /// <summary>
        /// Returns an <see cref="IEnumerator{T}"/> that enumerates the rows of this matrix.
        /// </summary>
        /// <param name="range">The <paramref name="range"/> of rows to enumerate over.</param>
        /// <returns>An <see cref="IEnumerator{T}"/> that enumerates over a given <see cref="Range"/> of rows of this matrix.</returns>
        /// <remarks>The enumerator returns a <seealso cref="KeyValuePair{T,K}"/> with the key being the row index and the value 
        /// being the that row as a <see cref="Vector"/>.</remarks>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="range"/> specifies a range of rows that is
        /// outside the number of matrix rows. </exception>
        /// <seealso cref="KeyValuePair{T,K}"/>
        /// <seealso cref="IEnumerator{T}"/>
        /// <include file='../../../examples/trunk/LinearAlgebra/MatrixRowEnumeratorRange.xml' path='example'/> 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public virtual IEnumerable<KeyValuePair<int, Vector>> RowEnumerator(Range range)
        {
            if (range.Start >= Rows || range.End >= Rows)
            {
                throw new ArgumentOutOfRangeException("range", Strings.OutOfRangeException);
            }
            for (int i = range.Start; i <= range.End; i += range.Stride)
            {
                yield return new KeyValuePair<int, Vector>(i, Row(i));
            }
        }

        /// <summary>
        /// Returns an <see cref="IEnumerator{T}"/> that enumerates the rows of this matrix.
        /// </summary>
        /// <returns>An <see cref="IEnumerator{T}"/> that enumerates over a given <see cref="Range"/> of rows of this matrix.</returns>
        /// <remarks>The enumerator returns a <seealso cref="KeyValuePair{T,K}"/> with the key being the row index and the value 
        /// being the that row as a <see cref="Vector"/>.</remarks>
        /// <seealso cref="KeyValuePair{T,K}"/>
        /// <seealso cref="IEnumerator{T}"/>
        /// <include file='../../../examples/trunk/LinearAlgebra/MatrixRowEnumerator.xml' path='example'/> 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public virtual IEnumerable<KeyValuePair<int, Vector>> RowEnumerator()
        {
            for (int i = 0; i < Rows; i++)
            {
                yield return new KeyValuePair<int, Vector>(i, Row(i));
            }
        }

        ///<summary>Calculates the condition number of this matrix.</summary>
        ///<returns>The condition number of the matrix.</returns>
        ///<remarks>For sparse matrices, the condition number is computed using a dense implementation of singular value decomposition. 
        /// In a later release, it will be replaced with a sparse implementation.</remarks>
        /// <exception cref="NotSupportedException">If the library is running on MS Windows and using <b>CLAPACK</b>
        /// as the <see cref="dnAnalytics.LinearAlgebra.Native.LapackProvider"/>.</exception>
        /// <remarks><b>This method is not supported under MS Windows when using the CLAPACK library.</b></remarks>
        public virtual double ConditionNumber()
        {
            if (Settings.UseNativeLibrary && Settings.Lapack == dnAnalytics.LinearAlgebra.Native.LapackProvider.Clapack && Environment.OSVersion.Platform != PlatformID.Unix)
            {
                throw new NotSupportedException(Strings.ClapackNotSupported);
            }

            Svd svd = new Svd(this, false);
            return svd.ConditionNumber();
        }

        /// <summary>
        /// Copies the elements of this matrix to the given matrix.
        /// </summary>
        /// <param name="target">The matrix to copy values into.</param>
        /// <exception cref="ArgumentNullException">If target is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If target is not the same size as this matrix.</exception>
        public virtual void CopyTo(Matrix target)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target", Strings.NullParameterException);
            }

            if (rows != target.Rows || columns != target.Columns)
            {
                throw new NotConformableException("target", Strings.ParameterNotConformable);
            }

            IEnumerable<KeyValuePair<int, Vector>> cols = this.ColumnEnumerator();
            foreach(KeyValuePair<int,Vector> column in ColumnEnumerator()){
                foreach (KeyValuePair<int, double> element in column.Value)
                {
                    target.ValueAt(element.Key, column.Key, element.Value);
                }
            }
        }

        /// <summary>Computes the determinant of this matrix.</summary>
        /// <returns>The determinant of this matrix.</returns>
        /// <exception cref="NotSquareMatrixException">If the matrix is not square.</exception>
        /// <remarks>For sparse matrices, the determinant is computed using a dense implementation of LU decomposition. 
        /// In a later release, it will be replaced with a sparse implementation.</remarks>
        public virtual double Determinant()
        {
            if (Rows != Columns)
            {
                throw new NotSquareMatrixException(Strings.MustBeSquare);
            }
            LU lu = new LU(this);
            return lu.Determinant();
        }

        /// <summary>
        /// Copies the diagonal elements of this matrix into the given <see cref="Vector"/>.
        /// </summary>
        /// <param name="vector">The vector to copy the diagonal elements into.</param>
        /// <exception cref="ArgumentNullException">If vector is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the size of the vector is not <b>Min(this.Rows, this.Columns)</b>.</exception>
        /// <remarks>For non-square matrices, the method returns Min(Rows, Columns) elements where
        /// i == j (i is the the row index, and j is the column index).</remarks>
        public virtual void Diagonal(Vector vector)
        {
            if (vector == null)
            {
                throw new ArgumentNullException("vector", Strings.NullParameterException);
            }

            int size = System.Math.Min(Rows, Columns);
            if (vector.Count != size)
            {
                throw new NotConformableException("vector", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < size; i++)
            {
                vector[i] = this.ValueAt(i, i);
            }
        }

        /// <summary>
        /// Returns the elements of the diagonal in a <see cref="Vector"/>.
        /// </summary>
        /// <returns>The elements of the diagonal.</returns>
        /// <remarks>For non-square matrices, the method returns Min(Rows, Columns) elements where
        /// i == j (i is the the row index, and j is the column index).</remarks>
        public virtual Vector Diagonal()
        {
            int size = System.Math.Min(Rows, Columns);
            Vector result = VectorBuilder.CreateVector(size, VectorType.Dense);
            Diagonal(result);
            return result;
        }

        /// <summary>
        /// Returns the transpose of this matrix.
        /// </summary>        
        /// <returns>The transpose of this matrix.</returns>
        public virtual Matrix Transpose()
        {
            Matrix result = CreateMatrix(Columns, Rows);
            Transpose(result);
            return result;
        }

        /// <summary>
        /// Copies the transpose of this matrix into the result matrix.
        /// </summary>
        /// <param name="result">The result of the transpose.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not <b>this.Columns x this.Rows</b>.</exception>
        public virtual void Transpose(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (this.Columns != result.Rows || this.Rows != result.Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            for (int j = 0; j < columns; j++)
            {
                for (int i = 0; i < rows; i++)
                {
                    result.ValueAt(j, i, this.ValueAt(i, j));
                }
            }
        }

        /// <summary>
        /// Returns the inverse of this matrix. The inverse is calculated using LU decomposition.
        /// </summary>
        /// <returns>The inverse of this matrix.</returns>
        /// <exception cref="NotSquareMatrixException">If this matrix is not square.</exception>
        /// <remarks>For sparse matrices, the inverse is computed using a dense implementation of LU decomposition. In a later release,
        /// it will be replaced with a sparse implementation of LU.</remarks>
        public virtual Matrix Inverse()
        {
            if (Rows != Columns)
            {
                throw new NotSquareMatrixException(Strings.MustBeSquare);
            }
            Matrix result = CreateMatrix(rows, columns);
            Inverse(result);
            return result;
        }

        /// <summary>
        /// Places the inverse of this matrix into the result matrix. The inverse is calculated using LU decomposition.
        /// </summary>
        /// <param name="result">A matrix to hold the inverse of this matrix.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception> 
        /// <exception cref="NotSquareMatrixException">If this matrix is not square.</exception>
        /// <remarks>For sparse matrices, the inverse is computed using a dense implementation of LU decomposition. In a later release,
        /// it will be replaced with a sparse implementation of LU.</remarks>
        public virtual void Inverse(Matrix result)
        {
            if (Rows != Columns)
            {
                throw new NotSquareMatrixException(Strings.MustBeSquare);
            }
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (result.Rows != this.Rows && result.Columns != this.Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            LU lu = new LU(this);
            lu.Inverse(result);
        }

        /// <summary>
        /// Copies the values of the given <see cref="Vector"/> to the specified column.
        /// </summary>
        /// <param name="index">The column to copy the values to.</param>
        /// <param name="source">The vector to copy the values from.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/> is <b>null</b>.</exception>        
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is less than zero,
        /// or greater than or equal to the number of columns.</exception>
        /// <exception cref="NotConformableException">If the size of <paramref name="source"/> does not
        /// equal the number of rows of this <b>Matrix</b>.</exception>
        public virtual void SetColumn(int index, Vector source)
        {
            if (index < 0 || index >= Columns)
            {
                throw new ArgumentOutOfRangeException("index", Strings.OutOfRangeException);
            }

            if (source == null)
            {
                throw new ArgumentNullException("source", Strings.NullParameterException);
            }

            if (source.Count != Rows)
            {
                throw new NotConformableException("source", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Rows; i++)
            {
                this.ValueAt(i, index, source[i]);
            }
        }

        /// <summary>
        /// Copies the values of the given array to the specified column.
        /// </summary>
        /// <param name="index">The column to copy the values to.</param>
        /// <param name="source">The array to copy the values from.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/> is <b>null</b>.</exception>        
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is less than zero,
        /// or greater than or equal to the number of columns.</exception>
        /// <exception cref="NotConformableException">If the size of <paramref name="source"/> does not
        /// equal the number of rows of this <b>Matrix</b>.</exception>
        /// <exception cref="NotConformableException">If the size of <paramref name="source"/> does not
        /// equal the number of rows of this <b>Matrix</b>.</exception>
        public virtual void SetColumn(int index, double[] source)
        {
            if (index < 0 || index >= Columns)
            {
                throw new ArgumentOutOfRangeException("index", Strings.OutOfRangeException);
            }

            if (source == null)
            {
                throw new ArgumentNullException("source", Strings.NullParameterException);
            }

            if (source.Length != Rows)
            {
                throw new NotConformableException("source", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Rows; i++)
            {
                this.ValueAt(i, index, source[i]);
            }
        }

        /// <summary>
        /// Copies the values of the given <see cref="Vector"/> to the diagonal.
        /// </summary>
        /// <param name="source">The vector to copy the values from. The length of the vector should be
        /// Min(Rows, Columns).</param>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/> is <b>null</b>.</exception>   
        /// <exception cref="NotConformableException">If the length of <paramref name="source"/> does not
        /// equal Min(Rows, Columns).</exception>
        /// <remarks>For non-square matrices, the elements of <paramref name="source"/> are copied to
        /// this[i,i].</remarks>
        public virtual void SetDiagonal(Vector source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source", Strings.NullParameterException);
            }

            int min = System.Math.Min(Rows, Columns);
            if (source.Count != min)
            {
                throw new NotConformableException("source", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < min; i++)
            {
                this.ValueAt(i, i, source[i]);
            }
        }

        /// <summary>
        /// Copies the values of the given array to the diagonal.
        /// </summary>
        /// <param name="source">The array to copy the values from. The length of the array should be
        /// Min(Rows, Columns).</param>
        /// <exception cref="ArgumentNullException">if <paramref name="source"/> is <b>null</b>.</exception>        
        /// <exception cref="NotConformableException">If the length of <paramref name="source"/> does not
        /// equal Min(Rows, Columns).</exception>
        /// <remarks>For non-square matrices, the elements of <paramref name="source"/> are copied to
        /// this[i,i].</remarks>
        public virtual void SetDiagonal(double[] source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source", Strings.NullParameterException);
            }

            int min = System.Math.Min(Rows, Columns);
            if (source.Length != min)
            {
                throw new NotConformableException("source", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < min; i++)
            {
                this.ValueAt(i, i, source[i]);
            }
        }

        /// <summary>
        /// Copies the values of the given <see cref="Vector"/> to the specified row.
        /// </summary>
        /// <param name="index">The row to copy the values to.</param>
        /// <param name="source">The vector to copy the values from.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/> is <b>null</b>.</exception>            
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is less than zero,
        /// or greater than or equal to the number of rows.</exception>
        /// <exception cref="NotConformableException">If the size of <paramref name="source"/> does not
        /// equal the number of columns of this <b>Matrix</b>.</exception>
        public virtual void SetRow(int index, Vector source)
        {
            if (index < 0 || index >= Rows)
            {
                throw new ArgumentOutOfRangeException("index", Strings.OutOfRangeException);
            }

            if (source == null)
            {
                throw new ArgumentNullException("source", Strings.NullParameterException);
            }

            if (source.Count != Columns)
            {
                throw new NotConformableException("source", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Columns; i++)
            {
                this.ValueAt(index, i, source[i]);
            }
        }

        /// <summary>
        /// Copies the values of the given array to the specified row.
        /// </summary>
        /// <param name="index">The row to copy the values to.</param>
        /// <param name="source">The array to copy the values from.</param>
        /// <remarks>If the number of elements in the array differs from the
        /// number of rows in this matrix, then min( columns, source.Length )
        /// elements are copied.</remarks>
        /// <exception cref="ArgumentNullException">If <paramref name="source"/> is <b>null</b>.</exception>  
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="index"/> is less than zero,
        /// or greater than or equal to the number of rows.</exception>
        /// <exception cref="NotConformableException">If the size of <paramref name="source"/> does not
        /// equal the number of columns of this <b>Matrix</b>.</exception>
        public virtual void SetRow(int index, double[] source)
        {
            if (index < 0 || index >= Rows)
            {
                throw new ArgumentOutOfRangeException("index", Strings.OutOfRangeException);
            }

            if (source == null)
            {
                throw new ArgumentNullException("source", Strings.NullParameterException);
            }

            if (source.Length != Columns)
            {
                throw new NotConformableException("source", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < Columns; i++)
            {
                this.ValueAt(index, i, source[i]);
            }
        }

        /// <summary>
        /// Returns a new matrix containing the lower triangle of this matrix.
        /// </summary>
        /// <returns>The lower triangle of this matrix.</returns>        
        public virtual Matrix LowerTriangle()
        {
            Matrix result = CreateMatrix(Rows, Columns);
            LowerTriangle(result);
            return result;
        }

        /// <summary>
        /// Puts the the lower triangle of this matrix into the result matrix.
        /// </summary>
        /// <param name="result">Where to store the the lower triangle.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void LowerTriangle(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Rows != rows || result.Columns != columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            result.Clear();
            for (int j = 0; j < columns; j++)
            {
                for (int i = 0; i < rows; i++)
                {
                    if (i >= j)
                    {
                        result.ValueAt(i, j, this.ValueAt(i, j));
                    }
                }
            }
        }

        /// <summary>
        /// Returns a new matrix containing the lower triangle of this matrix. The new matrix
        /// does not contain the diagonal elements of this matrix.
        /// </summary>
        /// <returns>The lower triangle of this matrix.</returns>
        public virtual Matrix StrictlyLowerTriangle()
        {
            Matrix result = CreateMatrix(Rows, Columns);
            StrictlyLowerTriangle(result);
            return result;
        }

        /// <summary>
        /// Puts the the lower triangle of this matrix into the result matrix. The result matrix doesn't 
        /// contain the diagonal elements of this matrix.
        /// </summary>
        /// <param name="result">Where to store the the lower triangle.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>  
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void StrictlyLowerTriangle(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Rows != rows || result.Columns != columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            result.Clear();
            for (int j = 0; j < columns; j++)
            {
                for (int i = 0; i < rows; i++)
                {
                    if (i > j)
                    {
                        result.ValueAt(i, j, this.ValueAt(i, j));
                    }
                }
            }
        }

        /// <summary>
        /// Returns a new matrix containing the upper triangle of this matrix.
        /// </summary>
        /// <returns>The upper triangle of this matrix.</returns>   
        public virtual Matrix UpperTriangle()
        {
            Matrix result = CreateMatrix(Rows, Columns);
            UpperTriangle(result);
            return result;
        }

        /// <summary>
        /// Puts the the upper triangle of this matrix into the result matrix.
        /// </summary>
        /// <param name="result">Where to store the the upper triangle.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void UpperTriangle(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Rows != Rows || result.Columns != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            result.Clear();
            for (int j = 0; j < Columns; j++)
            {
                for (int i = 0; i < Rows; i++)
                {
                    if (i <= j)
                    {
                        result.ValueAt(i, j, this.ValueAt(i, j));
                    }
                }
            }
        }

        /// <summary>
        /// Returns a new matrix containing the upper triangle of this matrix. The new matrix
        /// does not contain the diagonal elements of this matrix.
        /// </summary>
        /// <returns>The upper triangle of this matrix.</returns>
        public virtual Matrix StrictlyUpperTriangle()
        {
            Matrix result = CreateMatrix(Rows, Columns);
            StrictlyUpperTriangle(result);
            return result;
        }

        /// <summary>
        /// Puts the the upper triangle of this matrix into the result matrix. The result matrix doesn't 
        /// contain the diagonal elements of this matrix.
        /// </summary>
        /// <param name="result">Where to store the the upper triangle.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>          
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void StrictlyUpperTriangle(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Rows != Rows || result.Columns != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            result.Clear();
            for (int j = 0; j < Columns; j++)
            {
                for (int i = 0; i < Rows; i++)
                {
                    if (i < j)
                    {
                        result.ValueAt(i, j, this.ValueAt(i, j));
                    }
                }
            }
        }

        /// <summary>
        /// Creates a matrix that contains the values of this matrix for the given ranges.
        /// The size of the new matrix is determined by the ranges.
        /// </summary>
        /// <param name="rowRange">The <see cref="Range"/> of rows to copy into the new matrix.</param>
        /// <param name="columnRange">The <see cref="Range"/> of columns to copy into the new matrix.</param>
        /// <returns>A sub-matrix of this matrix for the given ranges.</returns>
        /// <exception cref="ArgumentOutOfRangeException">If either <paramref name="rowRange"/> or <paramref name="columnRange"/> 
        /// specify a <see cref="Range"/> outside the dimensions of the matrix.</exception>
        public virtual Matrix SubMatrix(Range rowRange, Range columnRange)
        {
            if (rowRange.Start >= Rows || rowRange.End >= Rows)
            {
                throw new ArgumentOutOfRangeException("rowRange", Strings.OutOfRangeException);
            }

            if (columnRange.Start >= Columns || columnRange.End >= Columns)
            {
                throw new ArgumentOutOfRangeException("columnRange", Strings.OutOfRangeException);
            }

            int numberOfRows = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            int numberOfColumns = (columnRange.End - columnRange.Start) / columnRange.Stride + 1;
            Matrix result = CreateMatrix(numberOfRows, numberOfColumns);
            SubMatrix(rowRange, columnRange, result);
            return result;
        }

        /// <summary>
        /// Copies a sub-matrix of this matrix into a given matrix.
        /// </summary>
        /// <param name="rowRange">The <see cref="Range"/> of rows to copy into the given matrix.</param>
        /// <param name="columnRange">The <see cref="Range"/> of columns to copy into the given matrix.</param>
        /// <param name="result">The matrix to copy the sub-matrix into.</param>
        /// <exception cref="ArgumentOutOfRangeException">If either <paramref name="rowRange"/> or <paramref name="columnRange"/> 
        /// specify a <see cref="Range"/> outside the dimensions of the matrix.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as those defined by the <b>Ranges</b>.</exception>
        public virtual void SubMatrix(Range rowRange, Range columnRange, Matrix result)
        {
            if (rowRange.Start >= Rows || rowRange.End >= Rows)
            {
                throw new ArgumentOutOfRangeException("rowRange", Strings.OutOfRangeException);
            }

            if (columnRange.Start >= Columns || columnRange.End >= Columns)
            {
                throw new ArgumentOutOfRangeException("columnRange", Strings.OutOfRangeException);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            int m = (rowRange.End - rowRange.Start) / rowRange.Stride + 1;
            int n = (columnRange.End - columnRange.Start) / columnRange.Stride + 1;
            if (result.Rows != m || result.Columns != n)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            for (int j = columnRange.Start, jj = 0; j <= columnRange.End; j += columnRange.Stride, jj++)
            {
                for (int i = rowRange.Start, ii = 0; i <= rowRange.End; i += rowRange.Stride, ii++)
                {
                    result.ValueAt(ii, jj, this.ValueAt(i, j));
                }
            }
        }

        /// <summary>
        /// Copies the value of a <b>Matrix</b> into this <b>Matrix</b> stating at the given
        /// <paramref name="row"/> and <paramref name="column"/>.
        /// </summary>
        /// <param name="row">The row of this <b>Matrix</b> to start copying the values to.</param>
        /// <param name="column">The column of this <b>Matrix</b> to start copying the values to.</param>
        /// <param name="subMatrix">The <b>Matrix</b> to copy the values from.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="subMatrix"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <list type="bullet">
        /// <item><term>row</term><description>The given row is greater than or equal to the number of rows of this <b>Matrix</b>.</description></item>
        /// <item><term>column</term><description>The given column is greater than or equal to the number of columns of this <b>Matrix</b>.</description></item>
        /// <item><term>subMatrix</term><description>The sub-matrix does not fit into this <b>Matrix</b>.</description></item>
        /// </list></exception>
        public virtual void SetSubMatrix(int row, int column, Matrix subMatrix)
        {
            if (subMatrix == null)
            {
                throw new ArgumentNullException("subMatrix", Strings.NullParameterException);
            }

            if (row >= rows)
            {
                throw new ArgumentOutOfRangeException("row", Strings.OutOfRangeException);
            }

            if (column >= columns)
            {
                throw new ArgumentOutOfRangeException("column", Strings.OutOfRangeException);
            }

            if (row + subMatrix.rows > rows || column + subMatrix.columns > columns)
            {
                throw new ArgumentOutOfRangeException("subMatrix", Strings.OutOfRangeException);
            }

            for (int i = 0; i < subMatrix.rows; i++)
            {
                for (int j = 0; j < subMatrix.columns; j++)
                {
                    ValueAt(i + row, j + column, subMatrix.ValueAt(i, j));
                }
            }
        }

        /// <summary>
        /// Returns this matrix as a multidimensional array.
        /// </summary>
        /// <returns>A multidimensional containing the values of this matrix.</returns>        
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Body"), SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Return")]
        public virtual double[,] ToArray()
        {
            double[,] ret = new double[Rows, Columns];
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Columns; j++)
                {
                    ret[i, j] = this.ValueAt(i, j);
                }
            }
            return ret;
        }

        /// <summary>
        /// Returns the matrix's elements as an array with data laid column wise.
        /// </summary>
        /// <example><pre>
        /// 1, 2, 3
        /// 4, 5, 6  will be returned as  1, 4, 7, 2, 5, 8, 3, 6, 9
        /// 7, 8, 9
        /// </pre></example>
        /// <returns>An array containing the matrix's elements.</returns>
        public virtual double[] ToColumnWiseArray()
        {
            double[] ret = new double[rows * columns];
            foreach( KeyValuePair<int, Vector> column in ColumnEnumerator()){
                int jIndex = column.Key * rows;
                foreach (KeyValuePair<int, double> element in column.Value)
                {
                    ret[jIndex + element.Key] = element.Value;
                }
            }

            return ret;
        }

        /// <summary>
        /// Returns the matrix's elements as an array with data laid row wise.
        /// </summary>
        /// <example><pre>
        /// 1, 2, 3
        /// 4, 5, 6  will be returned as  1, 2, 3, 4, 5, 6, 7, 8, 9
        /// 7, 8, 9
        /// </pre></example>
        /// <returns>An array containing the matrix's elements.</returns>
        public virtual double[] ToRowWiseArray()
        {
            double[] ret = new double[rows * columns];

            foreach (KeyValuePair<int, Vector> row in RowEnumerator())
            {
                int iIndex = row.Key * columns;
                foreach (KeyValuePair<int, double> element in row.Value)
                {
                    ret[iIndex + element.Key] = element.Value;
                }
                
            }
            return ret;
        }

        /// <summary>
        /// Returns a clone of this matrix.
        /// </summary>
        /// <returns>A clone of this matrix.</returns>
        /// <remarks>Added as an alternative to the unary addition operator.</remarks>
        public virtual Matrix Plus()
        {
            return this.Clone();
        }

        /// <summary>
        /// Adds a scalar to each element in the matrix overwriting the values of this matrix.
        /// </summary>
        /// <param name="scalar">The scalar to add.</param>        
        public virtual void Add(double scalar)
        {
            // First check if a is equal to zero. If so
            // then we can just exit
            if (System.Math.Abs(scalar) < Double.Epsilon)
            {
                return;
            }

            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Columns; j++)
                {
                    this.ValueAt(i, j, this.ValueAt(i, j) + scalar);
                }
            }
        }

        /// <summary>
        /// Adds a scalar to each element in the matrix and places the results into the result matrix.
        /// </summary>
        /// <param name="scalar">The scalar to add.</param>
        /// <param name="result">The results of the addition.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void Add(double scalar, Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (result.Rows != Rows || result.Columns != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            this.CopyTo(result);
            result.Add(scalar);
        }

        /// <summary>
        /// Adds another matrix to this matrix overwriting the values of this matrix.
        /// </summary>
        /// <param name="other">The matrix to add to this matrix.</param>
        /// <exception cref="ArgumentNullException">If the other matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the two matrices don't have the same dimensions.</exception>
        public virtual void Add(Matrix other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }

            if (other.Rows != Rows || other.Columns != Columns)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            double tmp = 0;
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < columns; j++)
                {
                    tmp = this.ValueAt(i, j);
                    tmp += other.ValueAt(i, j);
                    this.ValueAt(i, j, tmp);
                }
            }
        }

        /// <summary>
        /// Adds another matrix to this matrix and places the results into the result matrix.
        /// </summary>
        /// <param name="other">The matrix to add to.</param>
        /// <param name="result">The results of the addition.</param>
        /// <exception cref="ArgumentNullException">If the other matrix is <b>null</b>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the two matrices don't have the same dimensions.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void Add(Matrix other, Matrix result)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }

            if (other.Rows != Rows || other.Columns != Columns)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Rows != Rows || result.Columns != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            CopyTo(result);
            result.Add(other);
        }

        /// <summary>
        /// Negates each element of this matrix.
        /// </summary>        
        public virtual void Negate()
        {
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Columns; j++)
                {
                    this.ValueAt(i, j, -this.ValueAt(i, j));
                }
            }
        }

        /// <summary>
        /// Negate each element of this matrix and place the results into to result matrix.
        /// </summary>
        /// <param name="result">The result of the negation.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">if the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void Negate(Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Rows != Rows || result.Columns != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            CopyTo(result);
            result.Negate();
        }

        /// <summary>
        /// Subtracts a scalar from each value in the matrix overwriting the values of this matrix.
        /// </summary>
        /// <param name="scalar">The scalar to subtract.</param>
        public virtual void Subtract(double scalar)
        {
            Add(-scalar);
        }

        /// <summary>
        /// Subtracts a scalar from each in the matrix and place the results into the result matrix.
        /// </summary>
        /// <param name="scalar">The scalar to subtract.</param>
        /// <param name="result">The result of the subtraction.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void Subtract(double scalar, Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (result.Rows != Rows || result.Columns != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            this.CopyTo(result);
            result.Subtract(scalar);
        }

        /// <summary>
        /// Subtracts another matrix from this matrix overwriting the values of this matrix.
        /// </summary>
        /// <param name="other">The matrix to subtract.</param>
        /// <exception cref="ArgumentNullException">If the other matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the two matrices don't have the same dimensions.</exception>
        public virtual void Subtract(Matrix other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }

            if (other.Rows != Rows || other.Columns != Columns)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < columns; j++)
                {
                    double tmp = this.ValueAt(i, j);
                    tmp -= other.ValueAt(i, j);
                    this.ValueAt(i, j, tmp);
                }
            }
        }

        /// <summary>
        /// Subtracts another matrix for this matrix and places the results into the result matrix.
        /// </summary>
        /// <param name="other">The matrix to subtract.</param>
        /// <param name="result">The results of the subtraction.</param>
        /// <exception cref="ArgumentNullException">If the other matrix is <b>null</b>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the two matrices don't have the same dimensions.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void Subtract(Matrix other, Matrix result)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }

            if (other.Rows != Rows || other.Columns != Columns)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Rows != Rows || result.Columns != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            CopyTo(result);
            result.Subtract(other);
        }

        /// <summary>
        /// Multiplies each element of this matrix with a scalar overwriting the values of this matrix.
        /// </summary>
        /// <param name="scalar">The scalar to multiply with.</param>
        public virtual void Multiply(double scalar)
        {
            // if double = 0.0 then just reset the
            // value count to zero
            if (System.Math.Abs(scalar) < Double.Epsilon)
            {
                Clear();
                return;
            }
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Columns; j++)
                {
                    this.ValueAt(i, j, this.ValueAt(i, j) * scalar);
                }
            }
        }

        /// <summary>
        /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
        /// </summary>
        /// <param name="scalar">The scalar to multiply the matrix with.</param>
        /// <param name="result">The matrix to multiply.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception> 
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void Multiply(double scalar, Matrix result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }
            if (result.Rows != Rows || result.Columns != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            this.CopyTo(result);
            result.Multiply(scalar);
        }

        /// <summary>
        /// Multiplies this matrix with another matrix and return the result.
        /// </summary>
        /// <param name="other">The matrix to multiply with.</param>
        /// <exception cref="NotConformableException">If <b>this.Columns != other.Rows</b>.</exception>        
        /// <exception cref="ArgumentNullException">If the other matrix is <b>null</b>.</exception>
        public virtual Matrix Multiply(Matrix other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }

            if (Columns != other.Rows)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }
            Matrix result = CreateMatrix(rows, other.columns);
            this.Multiply(other, result);
            return result;
        }

        /// <summary>
        /// Multiplies this matrix with another matrix and places the results into the result matrix.
        /// </summary>
        /// <param name="other">The matrix to multiply with.</param>
        /// <param name="result">The result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If the other matrix is <b>null</b>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>this.Columns != other.Rows</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the this.Rows x other.Columns.</exception>
        public virtual void Multiply(Matrix other, Matrix result)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other", Strings.NullParameterException);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (Columns != other.Rows)
            {
                throw new NotConformableException("other", Strings.ParameterNotConformable);
            }

            if (result.Rows != Rows || result.Columns != other.Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            int i, j, l;
            double s = 0;
            for (j = 0; j != other.columns; j++)
            {
                for (i = 0; i != rows; i++)
                {
                    s = 0;
                    for (l = 0; l != columns; l++)
                    {
                        s += this.ValueAt(i, l) * other.ValueAt(l, j);
                    }
                    result.ValueAt(i, j, s);
                }
            }
        }

        /// <summary>
        /// Multiplies this matrix by a vector and returns the results.
        /// </summary>
        /// <param name="rightSide">The vector to multiply with.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If rightSide is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>this.Columns != rightSide.Count</b>.</exception>
        public virtual Vector Multiply(Vector rightSide)
        {
            Vector ret = VectorBuilder.CreateVector(Rows);
            this.Multiply(rightSide, ret);
            return ret;
        }

        /// <summary>
        /// Multiplies this matrix with a vector and places the results into the result matrix.
        /// </summary>
        /// <param name="rightSide">The vector to multiply with.</param>
        /// <param name="result">The result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If rightSide is <b>null</b>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="dnAnalytics.Exceptions.NotConformableException">If <b>result.Count != this.Rows</b>.</exception>
        /// <exception cref="dnAnalytics.Exceptions.NotConformableException">If <b>this.Columns != rightSide.Count</b>.</exception>
        public virtual void Multiply(Vector rightSide, Vector result)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }

            if (Columns != rightSide.Count)
            {
                throw new NotConformableException("rightSide", Strings.ParameterNotConformable);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (Rows != result.Count)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            int i, j;
            double s = 0;
            for (i = 0; i != rows; i++)
            {
                s = 0;
                for (j = 0; j != columns; j++)
                {
                    s += this.ValueAt(i, j) * rightSide[j];
                }
                result[i] = s;
            }
        }

        /// <summary>
        /// Multiplies this matrix by a vector and returns the results. Note the operation is vector * matrix.
        /// </summary>
        /// <param name="leftSide">The vector to multiply with.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If leftSide is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>this.Rows != leftSide.Count</b>.</exception>
        public virtual Vector LeftMultiply(Vector leftSide)
        {
            Vector ret = VectorBuilder.CreateVector(Columns);
            LeftMultiply(leftSide, ret);
            return ret;
        }

        /// <summary>
        /// Multiplies this matrix with a vector and places the results into the result matrix. Note the operation is vector * matrix.
        /// </summary>
        /// <param name="leftSide">The vector to multiply with.</param>
        /// <param name="result">The result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If leftSide is <b>null</b>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>result.Count != this.Columns</b>.</exception>
        /// <exception cref="NotConformableException">If <b>this.Rows != leftSide.Count</b>.</exception>
        public virtual void LeftMultiply(Vector leftSide, Vector result)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }

            if (Rows != leftSide.Count)
            {
                throw new NotConformableException("leftSide", Strings.ParameterNotConformable);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (Columns != result.Count)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }
            int i, j;
            double s = 0;
            for (j = 0; j != columns; j++)
            {
                s = 0;
                for (i = 0; i != leftSide.Count; i++)
                {
                    s += leftSide[i] * this.ValueAt(i, j);
                }
                result[j] = s;
            }
        }

        /// <summary>
        /// Divides each element of the matrix by a scalar overwriting the values of this matrix.
        /// </summary>
        /// <param name="scalar">The scalar to divide by.</param>
        public virtual void Divide(double scalar)
        {
            Multiply(1 / scalar);
        }

        /// <summary>
        /// Divides this matrix by a scalar and places the results into the results matrix.
        /// </summary>
        /// <param name="scalar">The scalar to divide the matrix by.</param>
        /// <param name="result">The result of the division.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not the same as this matrix.</exception>
        public virtual void Divide(double scalar, Matrix result)
        {
            Multiply(1 / scalar, result);
        }

        /// <summary>
        /// Stacks this matrix on top of the given matrix, returns the combined matrix.
        /// </summary>
        /// <param name="lower">The matrix to stack this matrix upon.</param>
        /// <returns>The combined matrix.</returns>
        /// <exception cref="ArgumentNullException">If lower is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>upper.Columns != lower.Columns</b>.</exception>
        public virtual Matrix Stack(Matrix lower)
        {
            if (lower == null)
            {
                throw new ArgumentNullException("lower", Strings.NullParameterException);
            }

            if (lower.Columns != Columns)
            {
                throw new NotConformableException("lower", Strings.ParameterNotConformable);
            }

            Matrix result = CreateMatrix(Rows + lower.Rows, Columns);
            Stack(lower, result);
            return result;
        }

        /// <summary>
        /// Stacks this matrix on top of the given matrix and places the result into the result matrix.
        /// </summary>
        /// <param name="lower">The matrix to stack this matrix upon.</param>
        /// <param name="result">The combined matrix.</param>
        /// <exception cref="ArgumentNullException">If lower is <b>null</b>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>upper.Columns != lower.Columns</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not (this.Rows + lower.rows) x this.Columns.</exception>
        public virtual void Stack(Matrix lower, Matrix result)
        {
            if (lower == null)
            {
                throw new ArgumentNullException("lower", Strings.NullParameterException);
            }
            if (lower.Columns != Columns)
            {
                throw new NotConformableException("lower", Strings.ParameterNotConformable);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Rows != (Rows + lower.Rows) || result.Columns != Columns)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }


            for (int j = 0; j < Columns; j++)
            {
                for (int i = 0; i < Rows; i++)
                {
                    result.ValueAt(i, j, this.ValueAt(i, j));
                }
            }

            for (int j = 0; j < lower.Columns; j++)
            {
                for (int i = 0; i < lower.Rows; i++)
                {
                    result.ValueAt(i + Rows, j, lower.ValueAt(i, j));
                }
            }
        }

        /// <summary>
        /// Concatenates this matrix with the given matrix.
        /// </summary>
        /// <param name="right">The matrix to concatenate.</param>
        /// <returns>The combined matrix.</returns>
        /// <exception cref="ArgumentNullException">If right is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>this.Rows != right.Rows.</b></exception>
        public virtual Matrix Append(Matrix right)
        {
            if (right == null)
            {
                throw new ArgumentNullException("right", Strings.NullParameterException);
            }

            if (right.Rows != Rows)
            {
                throw new NotConformableException("right", Strings.ParameterNotConformable);
            }

            Matrix result = CreateMatrix(Rows, Columns + right.Columns);
            Append(right, result);
            return result;
        }

        /// <summary>
        /// Concatenates this matrix with the given matrix and places the result into the result matrix.
        /// </summary>
        /// <param name="right">The matrix to concatenate.</param>
        /// <param name="result">The combined matrix.</param>
        /// <exception cref="ArgumentNullException">If right is <b>null</b>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>this.Rows != right.Rows</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not this.Rows x (this.Columns + right.Columns).</exception>
        public virtual void Append(Matrix right, Matrix result)
        {
            if (right == null)
            {
                throw new ArgumentNullException("right", Strings.NullParameterException);
            }

            if (right.Rows != Rows)
            {
                throw new NotConformableException("right", Strings.ParameterNotConformable);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Columns != (Columns + right.Columns) || result.Rows != Rows)
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            for (int j = 0; j < Columns; j++)
            {
                for (int i = 0; i < Rows; i++)
                {
                    result.ValueAt(i, j, this.ValueAt(i, j));
                }
            }

            for (int j = 0; j < right.Columns; j++)
            {
                for (int i = 0; i < right.Rows; i++)
                {
                    result.ValueAt(i, j + Columns, right.ValueAt(i, j));
                }
            }
        }

        /// <summary>
        /// Diagonally stacks his matrix on top of the given matrix. The new matrix is a MxN matrix, 
        /// where M = this.Rows + lower.Rows and N = this.Columns + lower.Columns.
        /// The values of off the off diagonal matrices/blocks are set to zero.
        /// </summary>
        /// <param name="lower">The lower, right matrix.</param>
        /// <exception cref="ArgumentNullException">If lower is <b>null</b>.</exception>
        /// <returns>the combined matrix</returns>
        public virtual Matrix DiagonalStack(Matrix lower)
        {
            if (lower == null)
            {
                throw new ArgumentNullException("lower", Strings.NullParameterException);
            }

            Matrix result = CreateMatrix(Rows + lower.Rows, Columns + lower.Columns);
            DiagonalStack(lower, result);
            return result;
        }

        /// <summary>
        /// Diagonally stacks his matrix on top of the given matrix and places the combined matrix into the result matrix.
        /// </summary>
        /// <param name="lower">The lower, right matrix.</param>
        /// <param name="result">The combined matrix</param>
        /// <exception cref="ArgumentNullException">If lower is <b>null</b>.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the result matrix's dimensions are not (this.Rows + lower.rows) x (this.Columns + lower.Columns).</exception>
        public virtual void DiagonalStack(Matrix lower, Matrix result)
        {
            if (lower == null)
            {
                throw new ArgumentNullException("lower", Strings.NullParameterException);
            }

            if (result == null)
            {
                throw new ArgumentNullException("result", Strings.NullParameterException);
            }

            if (result.Rows != (Rows + lower.Rows) || result.Columns != (Columns + lower.Columns))
            {
                throw new NotConformableException("result", Strings.ParameterNotConformable);
            }

            for (int j = 0; j < Columns; j++)
            {
                for (int i = 0; i < Rows; i++)
                {
                    result.ValueAt(i, j, this.ValueAt(i, j));
                }
            }

            for (int j = 0; j < lower.Columns; j++)
            {
                for (int i = 0; i < lower.Rows; i++)
                {
                    result.ValueAt(i + Rows, j + Columns, lower.ValueAt(i, j));
                }
            }
        }

        ///<summary>A string representation of this matrix.</summary>
        ///<returns>The string representation of the value of <b>this</b> instance.</returns>
        public override string ToString()
        {
            return ToString(null, null);
        }

        ///<summary>A string representation of this matrix.</summary>
        ///<param name="format">A format specification.</param>
        ///<returns>The string representation of the value of <b>this</b> instance as specified by format.</returns>
        public virtual string ToString(string format)
        {
            return ToString(format, null);
        }

        ///<summary>A string representation of this matrix.</summary>
        ///<param name="formatProvider">An <see cref="IFormatProvider"/> that supplies culture-specific formatting information.</param>
        ///<returns>The string representation of the value of <b>this</b> instance as specified by provider.</returns>
        public virtual string ToString(IFormatProvider formatProvider)
        {
            return ToString(null, formatProvider);
        }

        ///<summary>A string representation of this matrix.</summary>
        ///<param name="format">A format specification.</param>
        ///<param name="formatProvider">An <see cref="IFormatProvider"/> that supplies culture-specific formatting information.</param>
        ///<returns>The string representation of the value of <b>this</b> instance as specified by format and provider.</returns>
        public virtual string ToString(string format, IFormatProvider formatProvider)
        {
            StringBuilder sb = new StringBuilder("Rows: ");
            sb.Append(Rows).Append(", cols: ").Append(Columns).Append(System.Environment.NewLine);

            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Columns; j++)
                {
                    sb.Append(ValueAt(i, j).ToString(format, formatProvider));
                    if (j != Columns - 1)
                    {
                        sb.Append(", ");
                    }
                }
                if (i != Rows - 1)
                {
                    sb.Append(System.Environment.NewLine);
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Returns a deep-copy clone of the <b>Matrix</b>.
        /// </summary>
        /// <returns>A deep-copy clone of the <b>Matrix</b>.</returns>
        public virtual Matrix Clone()
        {
            Matrix result = CreateMatrix(Rows, Columns);
            this.CopyTo(result);
            return result;
        }

        /// <summary>
        /// Returns a deep-copy clone of the <b>Matrix</b>.
        /// </summary>
        /// <returns>A deep-copy clone of the <b>Matrix</b>.</returns>
        Object ICloneable.Clone()
        {
            return this.Clone();
        }

        #endregion Public Methods

        #region Private Methods
        /// <summary>
        /// Checks to see if the indices are valid, if not it throws an ArgumentOutOfRangeException.
        /// </summary>
        private void RangeCheck(int row, int column)
        {
            if (row < 0 || row >= rows)
            {
                throw new ArgumentOutOfRangeException("row");
            }
            if (column < 0 || column >= columns)
            {
                throw new ArgumentOutOfRangeException("row");
            }
        }
        #endregion Private Methods

        #region Operators

        /// <summary>
        /// Returns a <b>Matrix</b> containing the same values of rightSide. 
        /// </summary>
        /// <remarks>This method is included for completeness.</remarks>
        /// <param name="rightSide">The matrix to get the values from.</param>
        /// <returns>A matrix containing a the same values as <paramref name="rightSide"/>.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Matrix operator +(Matrix rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            return rightSide.Clone();
        }

        /// <summary>
        /// Adds two matrices together and returns the results.
        /// </summary>
        /// <param name="leftSide">One of the matrices to add.</param>
        /// <param name="rightSide">One of the matrices to add.</param>
        /// <returns>The result of the addition.</returns>
        /// <exception cref="NotConformableException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Matrix operator +(Matrix leftSide, Matrix rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }

            if (leftSide.Rows != rightSide.Rows || leftSide.Columns != rightSide.Columns)
            {
                throw new NotConformableException(Strings.ParametersNotConformable);
            }

            Matrix ret = leftSide.Clone();
            ret.Add(rightSide);
            return ret;
        }

        /// <summary>
        /// Negates each element of the matrix.
        /// </summary>
        /// <param name="rightSide">The matrix to negate.</param>
        /// <returns>A matrix containing the negated values.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Matrix operator -(Matrix rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            Matrix ret = rightSide.Clone();
            ret.Negate();
            return ret;
        }

        /// <summary>
        /// Subtracts two matrices and returns the results.
        /// </summary>
        /// <param name="leftSide">The matrix to subtract from.</param>
        /// <param name="rightSide">The matrix to subtract.</param>
        /// <returns>The result of the subtraction.</returns>
        /// <exception cref="NotConformableException">If <paramref name="leftSide"/> and <paramref name="rightSide"/> don't have the same dimensions.</exception>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Matrix operator -(Matrix leftSide, Matrix rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }

            if (leftSide.Rows != rightSide.Rows || leftSide.Columns != rightSide.Columns)
            {
                throw new NotConformableException(Strings.ParametersNotConformable);
            }

            Matrix ret = leftSide.Clone();
            ret.Subtract(rightSide);
            return ret;
        }

        /// <summary>
        /// Divides a <b>Matrix</b> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The matrix to divide.</param>
        /// <param name="rightSide">The constant to divide the matrix by.</param>
        /// <returns>The result of the division.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <b>null</b>.</exception>
        public static Matrix operator /(Matrix leftSide, double rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }
            Matrix ret = leftSide.Clone();
            ret.Divide(rightSide);
            return ret;
        }

        /// <summary>
        /// Multiplies a <b>Matrix</b> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The matrix to multiply.</param>
        /// <param name="rightSide">The constant to multiply the matrix by.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> is <b>null</b>.</exception>
        public static Matrix operator *(Matrix leftSide, double rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }
            Matrix ret = leftSide.Clone();
            ret.Multiply(rightSide);
            return ret;
        }

        /// <summary>
        /// Multiplies a <b>Matrix</b> by a constant and returns the result.
        /// </summary>
        /// <param name="leftSide">The matrix to multiply.</param>
        /// <param name="rightSide">The constant to multiply the matrix by.</param>
        /// <returns>The result of the multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="rightSide"/> is <b>null</b>.</exception>
        public static Matrix operator *(double leftSide, Matrix rightSide)
        {
            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }
            Matrix ret = rightSide.Clone();
            ret.Multiply(leftSide);
            return ret;
        }

        /// <summary>
        /// Multiplies two matrices.
        /// </summary>
        /// <param name="leftSide">One of the matrices to multiply.</param>
        /// <param name="rightSide">One of the matrices to multiply.</param>
        /// <returns>The result of multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If the dimensions of <paramref name="leftSide"/> or <paramref name="rightSide"/> don't conform.</exception>
        public static Matrix operator *(Matrix leftSide, Matrix rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }

            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }

            if (leftSide.Columns != rightSide.Rows)
            {
                throw new NotConformableException(Strings.ParametersNotConformable);
            }
            return leftSide.Multiply(rightSide);
        }

        /// <summary>
        /// Multiplies a <b>Matrix</b> and a <see cref="Vector"/>.
        /// </summary>
        /// <param name="leftSide">The matrix to multiply.</param>
        /// <param name="rightSide">The vector to multiply.</param>
        /// <returns>The result of multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>leftSide.Columns ! = rightSide.Count</b>.</exception>
        public static Vector operator *(Matrix leftSide, Vector rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }

            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }

            if (leftSide.Columns != rightSide.Count)
            {
                throw new NotConformableException(Strings.ParametersNotConformable);
            }

            return leftSide.Multiply(rightSide);

        }

        /// <summary>
        /// Multiplies a <see cref="Vector"/> and a <b>Matrix</b>.
        /// </summary>
        /// <param name="leftSide">The vector to multiply.</param>
        /// <param name="rightSide">The matrix to multiply.</param>
        /// <returns>The result of multiplication.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="leftSide"/> or <paramref name="rightSide"/> is <b>null</b>.</exception>
        /// <exception cref="NotConformableException">If <b>leftSide.Count != rightSide.Rows</b>.</exception>
        public static Vector operator *(Vector leftSide, Matrix rightSide)
        {
            if (leftSide == null)
            {
                throw new ArgumentNullException("leftSide", Strings.NullParameterException);
            }

            if (rightSide == null)
            {
                throw new ArgumentNullException("rightSide", Strings.NullParameterException);
            }

            if (leftSide.Count != rightSide.Rows)
            {
                throw new NotConformableException(Strings.ParametersNotConformable);
            }

            return rightSide.LeftMultiply(leftSide);
        }

        #endregion Operators

    }
}
